using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;
using System.Linq;

namespace IQIGame.Onigao.Logic
{
    public partial class LevelEntity : BaseEntity
    {
        public class SyncTransformData : IReusableClass
        {
            public LgLevelSyncTransformType type;
            public float speedRatio;
            public EntityMoveDirType dirType;
            public int rotationY;

            public bool needSync => type != LgLevelSyncTransformType.None;

            public uint MaxStore => 5;

            public void AddMoveSync(float speedRatio, EntityMoveDirType dirType)
            {
                this.type = LgLevelSyncTransformType.Move;
                this.speedRatio = speedRatio;
                this.dirType = dirType;
            }

            public void AddRatateSync(int rotationY)
            {
                this.type = LgLevelSyncTransformType.Rotate;
                this.rotationY = rotationY;
            }

            public void OnReset()
            {
                type = LgLevelSyncTransformType.None;
                speedRatio = 0;
                dirType = EntityMoveDirType.None;
                rotationY = 0;
            }
        }

        private static Converter<ElevatorFloorData, bool> _convertElevatorToActiveList = x => x.isActive;

        /// <summary>
        /// GameplayConfig里的实体配置
        /// </summary>
        public LevelEntityConfig entityConfig => _entityConfig;
        /// <summary>
        /// 标签，由策划设置
        /// </summary>
        public HashSet<ushort> tags { get; private set; }

        /// <summary>
        /// 服务的执行次数，由策划编辑
        /// </summary>
        public int execCount { get; set; }
        /// <summary>
        /// 服务管理器
        /// </summary>
        public ServiceManager serviceMgr { get; private set; }
        /// <summary>
        /// 功能触发矩形范围
        /// </summary>
        public RectInt triggerRect { get; private set; }
        /// <summary>
        /// 功能触发范围检测高度
        /// </summary>
        public int triggerRectHalfHeight { get; private set; }
        /// <summary>
        /// 触发矩形范围带不带旋转
        /// </summary>
        public bool isTriggerRectRotated { get; private set; }
        /// <summary>
        /// 阻挡是否激活
        /// </summary>
        public bool isObstacleActive { get; private set; }
        /// <summary>
        /// 特殊功能触发范围
        /// </summary>
        public Vector3Logic triggerRectBoxSize
        {
            get
            {
                return new Vector3Logic(triggerRect.Width, triggerRectHalfHeight * 2, triggerRect.Height);
            }
        }
        /// <summary>
        /// 是否是存档点
        /// </summary>
        public bool isCheckPoint => HasDynamicParam(EntityDynamicParamType.CheckPoint);
        /// <summary>
        /// 是否是已激活的存档点
        /// </summary>
        public bool isCheckPointActive
        {
            get
            {
                EntityPropCheckPoint checkPointProp = GetDynamicProperty(EntityDynamicPropertyType.CheckPoint) as EntityPropCheckPoint;
                return checkPointProp != null && checkPointProp.isActive;
            }
        }
        /// <summary>
        /// 是否非持久化实体
        /// </summary>
        public bool isNonpersistent => entityConfig != null && entityConfig.isNonpersistent;
        /// <summary>
        /// 交互类型
        /// </summary>
        public byte interactType { get; private set; }
        /// <summary>
        /// 行为树是否生效
        /// </summary>
        public override bool isBehavTreeActive => isAvailable && (_routineActCom == null || !_routineActCom.isActive) && !isFreeze;
        /// <summary>
        /// 状态机是否生效
        /// </summary>
        public override bool isFsmAvailable => isBehavTreeActive;
        /// <summary>
        /// 是否动态避障单位
        /// </summary>
        protected override bool isNavAgent => IsMovableObstacle();
        /// <summary>
        /// 是否处于任意玩家的aoi区域
        /// </summary>
        public bool isInAOIArea => _aoiSubscribers.Count > 0;
        /// <summary>
        /// 行动（主要指ai，循环演出，寻路）是否停止
        /// 注意寻路，循环表演不能直接使用isBehavTreeActive或isFsmAvailable判断是否暂停而必须使用该属性
        /// 因为循环表演和ai是互斥的，而不是并列的
        /// </summary>
        public bool isFreeze => (!entityConfig.dontFreezeOnOutOfView && !isInAOIArea) || _isSystemPauseBehav;
        #region private fields
        /// <summary>
        /// 实体配置
        /// </summary>
        public LevelEntityConfig _entityConfig;
        /// <summary>
        /// 上一次的交互状态
        /// </summary>
        private byte _lastInteractType;
        /// <summary>
        /// 循环表演组件
        /// </summary>
        private LgEntityRoutineActComponent _routineActCom;
        /// <summary>
        /// 循环表演cid
        /// </summary>
        private int routineActCid;
        private LevelEntityCtorData InitData;
        private ConfigurableFSM stateMachine;
        /// <summary>
        /// 同步位置，旋转等变化的列表
        /// 优化同步频率用
        /// </summary>
        private List<SyncTransformData> _syncTransDataList = new List<SyncTransformData>(5);
        private float _syncTransElapsedTime = 0;
        /// <summary>
        /// aoi订阅者（player id）
        /// </summary>
        private HashSet<long> _aoiSubscribers = new HashSet<long>();
        #endregion

        public void Init(int id, LevelRegion region, LevelEntityCtorData data, bool init4Reset = false)
        {
            this.InitData = data;
            InnerInit(id, region, data.position, data.isActive, data.initDirEuler);
            if (data.mcid != 0)
            {
                this.region.gameplayConfig.entityMap.TryGetValue(data.mcid, out _entityConfig);
            }
            if (entityConfig == null)
            {
                LogicLog.LogError($"实体mcid为0。");
                return;
            }
            if (entityConfig.entityCid != 0)
            {
                CfgPhysicalEntity cfgEntity = TableCenter.physicalEntity.Get(entityConfig.entityCid);
                this.defaultMoveSpeed = cfgEntity.DefaultSpeed;
            }
            this.behaviourName = _entityConfig.behaviourName;
            this.stateMachineName = _entityConfig.stateMachineName;
            this.execCount = 0;
            this.interactType = data.interactType;
            this._lastInteractType = interactType;
            this.isObstacleActive = data.isObstacleActive;

            int tagsLen = data.tags == null ? 0 : data.tags.Count;
            this.tags = new HashSet<ushort>(tagsLen);
            for (int i = 0; i < tagsLen; i++)
            {
                ushort tag = data.tags[i];
                this.tags.Add(tag);
            }

            if (data.bindEffectResId != 0)
            {
                var prop = GetOrAddDynProperty<EntityPropEntityBindEffect>(EntityDynamicPropertyType.EntityBindEffect);
                prop.effectResCid = data.bindEffectResId;
                prop.bindPoint = data.effectBindPoint;
            }

            if (data.loopAudioCid != 0)
            {
                var prop = GetOrAddDynProperty<EntityPropAudio>(EntityDynamicPropertyType.Audio);
                prop.loopAudioCid = data.loopAudioCid;
            }

            if (entityConfig?.paramMap != null)
            {
                foreach (var kv in entityConfig.paramMap)
                {
                    BaseEntityDynamicParam dynamicParam = kv.Value;
                    if (dynamicParam is EntityParamTriggerRect)
                    {
                        EntityParamTriggerRect triggerRectParam = dynamicParam as EntityParamTriggerRect;
                        this.triggerRect = triggerRectParam.rect;
                        this.triggerRectHalfHeight = triggerRectParam.halfHeight;
                        this.isTriggerRectRotated = triggerRectParam.isRotatable;
                    }
                    else if (dynamicParam is EntityParamElevator)
                    {
                        EntityParamElevator elevatorParam = dynamicParam as EntityParamElevator;
                        EntityPropElevator elevatorProp = GetDynamicProperty(EntityDynamicPropertyType.Elevator) as EntityPropElevator;
                        if (elevatorProp == null)
                        {
                            elevatorProp = new EntityPropElevator();
                            AddDynamicProperty(elevatorProp);
                        }
                        elevatorProp.floorActiveList = elevatorProp.floorActiveList ?? new bool[elevatorParam.floors.Count];
                        //从存档获取的数据会在Init之后再计算一次，重设电梯位置，这里只关心配置初始默认楼层即可
                        elevatorProp.curFloor = elevatorParam.initStayFloor;
                        //data里有从data里取
                        for (int i = 0; i < data.elevatorFloorActive.Count; i++)
                        {
                            elevatorProp.floorActiveList[i] = data.elevatorFloorActive[i];
                        }
                    }
                    else if (dynamicParam is EntityParamCheckPoint)
                    {
                        EntityPropCheckPoint checkPointProp = GetDynamicProperty(EntityDynamicPropertyType.CheckPoint) as EntityPropCheckPoint;
                        if (checkPointProp == null)
                        {
                            checkPointProp = new EntityPropCheckPoint();
                            AddDynamicProperty(checkPointProp);
                        }
                        //data里有从data里取
                        checkPointProp.isActive = data.isCheckPointActive;
                    }
                }
            }

            serviceMgr = serviceMgr ?? ClassPool.Get<ServiceManager>();
            serviceMgr.SetHost(this);
            serviceMgr.Refresh(data.services);
        }

        #region 根据pod刷新的方法
        /// <summary>
        /// 根据存档数据刷新初始化数据以外的数据
        /// config和pod重叠的数据不在这里处理，详情见LevelEntityCtorData注释
        /// </summary>
        /// <param name="levelEntityPOD">注意该值可能为null，为null为重置逻辑</param>
        public virtual void RefreshExtraFromSaveData(LevelEntityPOD levelEntityPOD)
        {
            //电梯比较特殊，楼层信息已经从LevelEntityCtorData中获取了，但这里依然要实时根据实体位置计算一次当前楼层
            //当前楼层是不存档的，因为它和实体的位置存在必然联系，可以计算获得
            EntityPropElevator elevatorProp = GetDynamicProperty(EntityDynamicPropertyType.Elevator) as EntityPropElevator;
            if (elevatorProp != null)
            {
                elevatorProp.curFloor = this.CalcElevatorFloor();
            }
            //初始化buff
            InitBuffs(levelEntityPOD?.normal.buffs);
            //区域特效
            List<int> effectCids = levelEntityPOD?.normal.areaEffectCids;
            EntityPropSceneEffect sceneEffectProp = GetDynamicProperty(EntityDynamicPropertyType.SceneEffect) as EntityPropSceneEffect;
            bool hasEffect = effectCids != null && effectCids.Count > 0;
            if (sceneEffectProp == null && hasEffect)
            {
                sceneEffectProp = new EntityPropSceneEffect();
                sceneEffectProp.effectIds = new List<int>(effectCids.Count);
                AddDynamicProperty(sceneEffectProp);
            }
            sceneEffectProp?.effectIds.Clear();
            if (hasEffect)
            {
                for (int i = 0; i < effectCids.Count; i++)
                {
                    sceneEffectProp.effectIds.Add(effectCids[i]);
                }
            }
            //惯常行为
            ResetRoutineActId(levelEntityPOD);
        }

        private void ResetRoutineActId(LevelEntityPOD levelEntityPOD)
        {
            routineActCid = levelEntityPOD == null ? 0 : levelEntityPOD.normal.routineActCid;
        }
        #endregion

        /// <summary>
        /// 开启行为树或状态机（二者至多生效一个）
        /// </summary>
        public void StartAI()
        {
            if (!string.IsNullOrEmpty(behaviourName))
            {
                bool isSuccess = SLevelLogicModule.Instance.BehaviacManager.ChangeAgent<LgLevelEntityBtAgent>(this, behaviourName);
                if (!isSuccess)
                {
                    LogicLog.LogError($"初始化行为树失败，实体mcid：{entityConfig.id}, 行为树名：{behaviourName}");
                }
            }
            else
            {
                SLevelLogicModule.Instance.StateMachineManager.RemoveFSM(this);
                stateMachine = null;
                if (!string.IsNullOrEmpty(stateMachineName))
                {
                    stateMachine = SLevelLogicModule.Instance.StateMachineManager.AddFSM(PathConstant.GetStateMachineConfigPath(stateMachineName), this);
                    if (stateMachine != null)
                    {
                        stateMachine.Start();
                    }
                    else
                    {
                        LogicLog.LogError($"初始化状态机失败，实体mcid：{entityConfig.id}, 状态机名：{stateMachineName}");
                    }
                }
            }
        }

        public void ResetAI()
        {
            if (!string.IsNullOrEmpty(behaviourName))
            {
                SLevelLogicModule.Instance.BehaviacManager.ChangeAgent<LgLevelEntityBtAgent>(this, behaviourName);
            }
            else
            {
                stateMachine?.Restart();
            }
        }

        public void SwitchEntityBehaviour(bool isPause)
        {
            this._isSystemPauseBehav = isPause;
        }

        public bool TryTriggerService(LevelPlayer player, ServiceTriggerType triggerType, object objectParam = null, TrigValueTypeParam valueTypeParam = default)
        {
            if (!isAvailable)
            {
                return false;
            }
            if (isOccupied)
            {
                LogicLog.LogError($"触发实体[mcid: {entityConfig.id}]的服务失败。实体处于占用状态：{DebugOccupationLog()}。");
                return false;
            }
            if (player != null)
            {
                if (player.entity.isOccupied)
                {
                    LogicLog.LogError($"触发实体[mcid: {entityConfig.id}]的服务失败。玩家处于占用状态：{player.entity.DebugOccupationLog()}。");
                    return false;
                }
                if (player.isTeamWipe) //由玩家触发，但玩家已经团灭，不能再触发服务
                {
                    return false;
                }
            }
            bool normalhasSuccess = serviceMgr.TryTrigger(player, triggerType, objectParam, valueTypeParam);
            bool buffhasSuccess = false;
            if (_buffManager != null && !IsNotAffectBuff(triggerType))
            {
                buffhasSuccess = _buffManager.TryTriggerService(triggerType);
            }
            return normalhasSuccess || buffhasSuccess;
        }

        /// <summary>
        /// 为了性能考虑，以下触发类型不触发buff内的服务
        /// </summary>
        /// <param name="triggerType"></param>
        /// <returns></returns>
        private bool IsNotAffectBuff(ServiceTriggerType triggerType)
        {
            switch (triggerType)
            {
                case ServiceTriggerType.None:
                case ServiceTriggerType.MoveInRange:
                case ServiceTriggerType.EntityStopNavigation:
                case ServiceTriggerType.NoServiceTiggeredWhenInteract:
                case ServiceTriggerType.SwitchPhysicalArea:
                    return true;
                default:
                    return false;
            }
        }

        public void EnableServiceUnit(int serviceId, int unitIndex, bool isEnabled)
        {
            serviceMgr.SetServiceUnitEnabled(serviceId, unitIndex, isEnabled);
        }

        public override bool SetActive(bool value)
        {
            bool isSuccess = base.SetActive(value);
            if (!isSuccess)
                return false;

            if (isActive)
            {
                ActiveFunction();
                ActiveRoutineAct(true);
            }
            else
            {
                DeactiveFunction();
                ActiveRoutineAct(false);

                ResetAI();
                StopExecNavigation();
            }

            if (value)
            {
                TryTriggerService(null, ServiceTriggerType.EntityBorn);
            }
            return true;
        }

        /// <summary>
        /// 激活实体基础功能
        /// </summary>
        public void ActiveFunction()
        {
            LevelRegionTerrain terrain = region.terrain;
            terrain.AddIntoQuadTree(this);
            if (this.HasTriggerRect())
            {
                terrain.AddIntoBvhTree(this);
            }
            if (isObstacleActive) //阻挡
            {
                region.AddEntityObstacle(this);
            }
            if (tags.Contains((ushort)LevelEntityTag.DefaultBorn)) //特殊缓存点
            {
                region.CacheSpeEntity(this, LevelEntityTag.DefaultBorn, true);
            }
            else if (tags.Contains((ushort)LevelEntityTag.CheckPoint)) //特殊缓存点，策划说出生点和存档点不会是一个点
            {
                region.CacheSpeEntity(this, LevelEntityTag.CheckPoint, true);
            }
        }

        /// <summary>
        /// 关闭实体基础功能
        /// </summary>
        private void DeactiveFunction()
        {
            LevelRegionTerrain terrain = region.terrain;
            terrain.RemoveFromQuadTree(this);
            if (this.HasTriggerRect())
            {
                terrain.RemoveFromBvhTree(this);
            }
            if (ObstacleId != 0) //阻挡
            {
                region.RemoveEntityObstacle(this);
            }
            if (tags.Contains((ushort)LevelEntityTag.CheckPoint) || tags.Contains((ushort)LevelEntityTag.DefaultBorn)) //特殊缓存点
            {
                region.CacheSpeEntity(this, LevelEntityTag.CheckPoint, false);
            }

            if (_buffManager != null)
            {
                _buffManager.RemoveAll();
            }
        }

        public override void LogicOnUpdate()
        {
            base.LogicOnUpdate();
            if (_syncTransDataList.Count > 0) //一定时间才同步一次实体位置变化给视图层
            {
                _syncTransElapsedTime += LgLevelConst.deltaTime;
                if (_syncTransElapsedTime >= LgLevelConst.MoveSyncInterval)
                {
                    _syncTransElapsedTime = 0;
                    foreach (var data in _syncTransDataList)
                    {
                        if (data.type == LgLevelSyncTransformType.Move)
                        {
                            region.NotifySyncPosition(null, LevelMoveReason.Move, LevelEntityType.Normal, this, position, data.speedRatio, data.dirType);
                        }
                        else if (data.type == LgLevelSyncTransformType.Rotate)
                        {
                            region.UpdateEntityRotationY(null, this, LevelEntityType.Normal, data.rotationY);
                        }
                        ClassPool.Put(data);
                    }

                    _syncTransDataList.Clear();
                }
            }
        }

        /// <summary>
        /// 是否是可移动的阻挡（非静态阻挡）
        /// 注意该方法不会判断entity.isAvailable，只关心阻挡，即便!isAvailable，只要是合法并生效的阻挡，依然会返回true
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool IsMovableObstacle()
        {
            return isObstacleActive && !entityConfig.obstacle.isStatic && ObstacleId != 0;
        }

        /// <summary>
        /// 更新位置，执行和位置有关的逻辑
        /// 注意网格寻路的计算应该在该方法调用之前
        /// </summary>
        /// <param name="position"></param>
        /// <param name="speedRatio">用于给视图层同步，代表相对于默认速度的比率</param>
        /// <param name="needSync">是否将结果同步给客户端</param>
        public override bool UpdateMove(Vector3Logic position, float speedRatio, bool needSync = true, EntityMoveDirType dirType = EntityMoveDirType.KeepVertical)
        {
            bool moved = base.UpdateMove(position, speedRatio, needSync, dirType);
            if (!moved)
            {
                return false;
            }
            region.terrain.MoveInQuadTree(this);
            if (this.HasTriggerRect())
            {
                region.terrain.MoveInBvhTree(this);
            }
            if (needSync)
            {
                TryAddMoveNotify(speedRatio, dirType);
            }
            return true;
        }

        public override bool MoveInNavMesh(Vector3Logic targetPoint, float speedRatio, bool needSync, EntityMoveDirType dirType = EntityMoveDirType.KeepVertical)
        {
            return base.MoveInNavMesh(targetPoint, speedRatio, needSync, dirType);
        }

        protected override bool TeleportInNavMesh(bool useAgentMove, Vector3Logic targetPoint)
        {
            if (navigator.isNavigating)
            {
                LogicLog.LogError("实体正在寻路，无法直接传送");
                return false;
            }
            return base.TeleportInNavMesh(useAgentMove, targetPoint);
        }

        public void UpdateRotation(Vector3Logic euler, bool syncToClient)
        {
            dirUnnormalized = Vector3Logic.EulerXyToDirection(euler, false);
            if (syncToClient)
            {
                TryAddRotateNotify((int)euler.y);
            }
        }

        private void TryAddMoveNotify(float speedRatio, EntityMoveDirType dirType)
        {
            var syncData = GenDataIntoSyncTransformList(LgLevelSyncTransformType.Move);
            syncData.AddMoveSync(speedRatio, dirType);
        }

        private void TryAddRotateNotify(int rotationY)
        {
            var syncData = GenDataIntoSyncTransformList(LgLevelSyncTransformType.Rotate);
            syncData.AddRatateSync(rotationY);
        }

        private SyncTransformData GenDataIntoSyncTransformList(LgLevelSyncTransformType syncType)
        {
            //取最后一个数据，如果不相同，则新建，相同则直接用它，目的是优化同步数量，例如同步周期内如果一直想要同步的只有Move，那只需要最终同步一次就行了
            //但如果中间插入了其他类型的同步，为了保证顺序，则必须新建一个添加上去
            var targetItem = _syncTransDataList.Count == 0 ? null : _syncTransDataList[_syncTransDataList.Count - 1];
            if (targetItem == null || targetItem.type != syncType)
            {
                targetItem = ClassPool.Get<SyncTransformData>();
                _syncTransDataList.Add(targetItem);
            }
            return targetItem;
        }

        /// <summary>
        /// 开始寻路
        /// </summary>
        /// <param name="targetPosition">目标位置</param>
        /// <param name="needWaitHero">英雄远离时是否等待</param>
        public bool StartNavigation(Vector3Logic targetPosition)
        {
            return navigator.NavigateTo(targetPosition, moveSpeed);
        }

        public bool StartNavigation(Vector3Logic targetPosition, int speed)
        {
            return navigator.NavigateTo(targetPosition, speed);
        }

        public bool StartNavigation(Vector3Logic targetPosition, bool needAdjustPos)
        {
            ValidTargetPos(needAdjustPos, targetPosition, out var realTargetPos);
            return navigator.NavigateTo(realTargetPos, moveSpeed);
        }

        public bool StartNavigation(Vector3Logic targetPosition, bool needAdjustPos, int speed)
        {
            ValidTargetPos(needAdjustPos, targetPosition, out var realTargetPos);
            return navigator.NavigateTo(realTargetPos, speed);
        }

        public bool StartNavigation(Vector3Logic targetPosition, bool needAdjustPos, int speed, int stopRotationY)
        {
            ValidTargetPos(needAdjustPos, targetPosition, out var realTargetPos);
            return navigator.NavigateTo(realTargetPos, speed, stopRotationY);
        }

        private bool ValidTargetPos(bool needAdjustPos, Vector3Logic targetPosition, out Vector3Logic realTargetPos)
        {
            if (!needAdjustPos)
            {
                realTargetPos = targetPosition;
                return true;
            }
            return region.terrain.FindNearestPoint(targetPosition, out realTargetPos);
        }

        /// <summary>
        /// 暂停寻路
        /// </summary>
        /// <param name="isStop">为真时停止寻路</param>
        public void PauseNavigation()
        {
            navigator.SetActive(false);
        }

        /// <summary>
        /// 停止寻路
        /// </summary>
        /// <param name="resetSpeed"></param>
        public void StopNavigation(bool resetSpeed = true)
        {
            navigator.StopNavigation(resetSpeed, position);
        }

        /// <summary>
        /// 停止寻路，可传入停止位置
        /// </summary>
        /// <param name="resetSpeed"></param>
        /// <param name="stopPos"></param>
        public void StopNavigation(bool resetSpeed, Vector3Logic stopPos)
        {
            navigator.StopNavigation(resetSpeed, stopPos);
        }

        public bool IsEntityInSight(BaseEntity target)
        {
            if (target.navigator.isPhysical)
            {
                return false;
            }
            if ((target.position - position).sqrMagnitude < entityConfig.viewRange * entityConfig.viewRange)
            {
                Vector3Logic thisToTarget = target.position - position;
                float dotProduct = Vector3Logic.Dot(thisToTarget.normalized, dir);

                // 计算视野角度的cos值
                if (LgMathUtil.FastCos(entityConfig.viewAngle / 2, out float cosFOV))
                {
                    // 判断是否在视野内，cos值越大θ越小
                    if (dotProduct >= cosFOV)
                    {
                        return true;
                    }
                }
                else
                {
                    LogicLog.LogError($"Entity.viewAngle is invalid: {entityConfig.viewAngle}");
                }
            }
            return false;
        }

        public void SetInteractType(byte value, bool syncToClientIfChanged)
        {
            if (interactType == value)
            {
                return;
            }
            _lastInteractType = interactType;
            interactType = value;
            if (syncToClientIfChanged)
            {
                region.UpdateEntity(null, this);
            }
        }

        public bool RecoverInteractType(bool syncToClientIfChanged)
        {
            if (interactType == _lastInteractType)
            {
                return false;
            }
            byte type = _lastInteractType;
            _lastInteractType = interactType;
            interactType = type;
            if (syncToClientIfChanged)
            {
                region.UpdateEntity(null, this);
            }
            return true;
        }

        public void OnRemove()
        {
            isRemoved = true;
            SLevelLogicModule.Instance.BehaviacManager.RemoveAgentFrom(this);
            ReleaseComponents();
            StopRoutineAct();
            if (_buffManager != null)
            {
                _buffManager.RemoveAll();
            }
            region.level.delayServiceMgr.CancelDelayByEntity(id);
        }

        public bool HasDynamicParam(EntityDynamicParamType type)
        {
            if (entityConfig?.paramMap == null)
            {
                return false;
            }
            return entityConfig.paramMap.ContainsKey(type);
        }

        public BaseEntityDynamicParam GetDynamicParam(EntityDynamicParamType type)
        {
            if (entityConfig?.paramMap == null)
            {
                return null;
            }
            if (entityConfig.paramMap.TryGetValue(type, out var paramData))
            {
                return paramData;
            }
            return null;
        }

        public void SetObstacleActive(bool value)
        {
            if (isObstacleActive == value)
            {
                return;
            }
            isObstacleActive = value;
            if (isObstacleActive && isAvailable)
            {
                region.AddEntityObstacle(this);
            }
            else
            {
                region.RemoveEntityObstacle(this);
            }
        }

        public void InitRoutineAct(int startActId)
        {
            routineActCid = startActId;
            RestartRoutineAct();
        }

        public void RestartRoutineAct()
        {
            if (_routineActCom == null)
            {
                _routineActCom = AddComponent<LgEntityRoutineActComponent>();
            }
            _routineActCom.Play(routineActCid);
        }

        public void ActiveRoutineAct(bool isActive)
        {
            if (routineActCid != 0 && _routineActCom != null)
            {
                if (isActive)
                {
                    _routineActCom.Active();
                    _routineActCom.Resume(); //IInterruptibleComponent接口，和Active逻辑不同
                }
                else
                {
                    _routineActCom.Pause();
                }
            }
        }

        public void StopRoutineAct()
        {
            if (_routineActCom != null)
            {
                _routineActCom.Stop();
                _routineActCom = null;
                RemoveComponent<LgEntityRoutineActComponent>();
            }
            routineActCid = 0;
        }

        public void ChangeSceneEffect(int effectCid, bool isAdd)
        {
            EntityPropSceneEffect sceneEffectProp = GetDynamicProperty(EntityDynamicPropertyType.SceneEffect) as EntityPropSceneEffect;
            if (isAdd && sceneEffectProp == null)
            {
                sceneEffectProp = new EntityPropSceneEffect();
                sceneEffectProp.effectIds = new List<int>();
                AddDynamicProperty(sceneEffectProp);
            }

            if (isAdd)
            {
                sceneEffectProp.effectIds.Add(effectCid);
            }
            else if (sceneEffectProp != null)
            {
                sceneEffectProp.effectIds.Remove(effectCid);
            }
        }

        public void ChangeBindEffect(int effectResid, int bindPoint, bool isAdd)
        {
            var prop = GetOrAddDynProperty<EntityPropEntityBindEffect>(EntityDynamicPropertyType.EntityBindEffect);
            if (isAdd)
            {
                prop.effectResCid = effectResid;
                prop.bindPoint = bindPoint;
            }
            else
            {
                prop.effectResCid = 0;
                prop.bindPoint = 0;
            }
        }

        public void FollowHero(LevelPlayer player)
        {
            LgFollowHeroComponent component = AddComponent<LgFollowHeroComponent>();
            component.SetHero(player.entity);
        }

        public void StopFollow(LevelPlayer player)
        {
            if (this == player.entityFollowingMe)
            {
                RemoveComponent<LgFollowHeroComponent>();
            }
        }

        /// <summary>
        /// 攻击玩家
        /// </summary>
        /// <param name="player"></param>
        public void Attack(LevelPlayer player)
        {
            TryTriggerService(player, ServiceTriggerType.UnderAttack);
        }

        /// <summary>
        /// 改变警戒状态
        /// </summary>
        /// <param name="detectedEnemyEntity"></param>
        /// <param name="alertValue"></param>
        public void ChangeAlertEnemy(BaseEntity enemyEntity, float alertValue)
        {
            region.UpdateEntityAlert(this, enemyEntity, (int)alertValue);
        }

        /// <summary>
        /// 实体重置
        /// </summary>
        public void Reset()
        {
            //停止执行寻路行为
            StopExecNavigation();
            //刷新惯常行为
            //必须在Init()之前，因为停止寻路会强制把实体设置到目标点，如果在Init之后，会导致position被刷成之前的目标点
            ResetRoutineActId(null);
            if (routineActCid == 0)
            {
                StopRoutineAct();
            }
            else
            {
                RestartRoutineAct();
            }
            //按照初始配置初始化
            Init(id, region, InitData, true);
            //刷新buff，电梯楼层，特效等在初始化时可能不会设置的动态功能数据
            RefreshExtraFromSaveData(null);
            //强制修改了位置数据后，刷新一下寻路网格的数据
            //仅动态阻挡会在寻路网格里保存数据
            if (IsMovableObstacle())
            {
                region.terrain.TeleportAgentTo(ObstacleId, position);
            }
            //重置AI
            ResetAI();
        }

        /// <summary>
        /// 停止由执行开启的寻路
        /// </summary>
        private void StopExecNavigation()
        {
            //判断如果有独立寻路（不是状态机，循环表演驱动的寻路），需要停止
            var navAssistantCom = GetComponent<LgNpcNavAssistantComponent>();
            if (navAssistantCom != null && !navAssistantCom.combinedWithOtherComponent)
            {
                navAssistantCom.StopAndDestroy();
            }
        }

        /// <summary>
        /// 生成pod
        /// </summary>
        /// <param name="isSave">是否为存档生成pod</param>
        /// <param name="simplifyIfRemoved">实体移除后，是否使用最简化的数据（无需再纪录详细数据）</param>
        /// <returns></returns>
        public LevelEntityPOD GeneratePOD(bool isSave, bool simplifyIfRemoved)
        {
            LevelEntityPOD pod = new LevelEntityPOD();
            pod.id = id;
            pod.type = LevelEntityType.Normal;
            pod.IsRemoved = isRemoved;
            LevelNormalEntityPOD normal = new LevelNormalEntityPOD();
            pod.normal = normal;
            normal.mcid = _entityConfig == null ? 0 : _entityConfig.id;
            if (simplifyIfRemoved && isRemoved)
            {
                return pod;
            }

            bool isReset = isSave && isNonpersistent;

            if (isReset)
            {
                pod.x = InitData.position.x;
                pod.y = InitData.position.y;
                pod.z = InitData.position.z;
            }
            else
            {
                if (isSave)
                {
                    Vector3Logic toSavePos = position;
                    //如果正在直线减速运动（如推箱子），保存终点位置为读档后的npc位置
                    LgEntityLinearMove moveCom = GetComponent<LgEntityLinearMove>();
                    if (moveCom != null)
                    {
                        toSavePos = moveCom.stopPoint;
                    }
                    else
                    {
                        //如果正在寻路，保存终点位置为读档后的npc位置(行为树，循环表演和执行寻路会使用该组件)
                        LgNpcNavAssistantComponent navAssistantCom = GetComponent<LgNpcNavAssistantComponent>();
                        if (navAssistantCom != null && !navAssistantCom.navIsComplete)
                        {
                            toSavePos = navAssistantCom.finalDestination;
                        }
                        else if (navigator.isNavigating)
                        {
                            toSavePos = navigator.destination;
                        }
                    }
                    pod.x = (int)toSavePos.x;
                    pod.y = (int)toSavePos.y;
                    pod.z = (int)toSavePos.z;
                }
                else
                {
                    pod.x = (int)position.x;
                    pod.y = (int)position.y;
                    pod.z = (int)position.z;
                }
            }

            Vector3Int eulerV3Int = isReset ? InitData.initDirEuler : Vector3Logic.DirectionToEulerXy(dir);
            pod.dirEuler = Vector3Int.ToIntEuler(eulerV3Int);

            pod.isActive = isReset ? InitData.isActive : isActive;
            normal.isObstacleActive = isReset ? InitData.isObstacleActive : isObstacleActive;
            normal.unsafe_tags = isReset ? InitData.tags?.ToList() : tags?.ToList();
            normal.execCount = isReset ? 0 : execCount;
            normal.unsafe_services = isReset ? entityConfig.services.ToList() : serviceMgr.ToServiceCidList();
            normal.interactType = isReset ? InitData.interactType : interactType;
            normal.unsafe_elevatorFloorActive = isReset ? GetInitElevatorFloorActive() : this.GetElevatorFloorActivation()?.ToList();
            normal.isCheckPointActive = isReset ? GetInitIsCheckPointActive() : isCheckPointActive;
            normal.unsafe_areaEffectCids = isReset ? null : (GetDynamicProperty(EntityDynamicPropertyType.SceneEffect) as EntityPropSceneEffect)?.effectIds?.Clone();
            var bindEfxProp = GetDynamicProperty(EntityDynamicPropertyType.EntityBindEffect) as EntityPropEntityBindEffect;
            normal.bindEffectRes = isReset ? InitData.bindEffectResId : (bindEfxProp == null ? 0 : bindEfxProp.effectResCid);
            normal.effectBindPoint = isReset ? InitData.effectBindPoint : (bindEfxProp == null ? 0 : bindEfxProp.bindPoint);
            var audioProp = GetDynamicProperty(EntityDynamicPropertyType.Audio) as EntityPropAudio;
            normal.loopAudio = isReset ? InitData.loopAudioCid : (audioProp == null ? 0 : audioProp.loopAudioCid);
            normal.unsafe_buffs = isReset ? null : _buffManager?.GenerateBuffPODs();
            normal.routineActCid = isReset ? 0 : routineActCid;
            return pod;
        }

        private List<bool> GetInitElevatorFloorActive()
        {
            var paramMap = entityConfig?.paramMap;
            if (paramMap == null)
            {
                return null;
            }
            if (paramMap.TryGetValue(EntityDynamicParamType.Elevator, out var dynamicParam))
            {
                EntityParamElevator elevatorParam = dynamicParam as EntityParamElevator;
                List<bool> result = (elevatorParam.floors as List<ElevatorFloorData>).ConvertAll(_convertElevatorToActiveList);
                return result;
            }
            return null;
        }

        private bool GetInitIsCheckPointActive()
        {
            var paramMap = entityConfig?.paramMap;
            if (paramMap == null)
            {
                return false;
            }
            if (paramMap.TryGetValue(EntityDynamicParamType.CheckPoint, out var dynamicParam))
            {
                EntityParamCheckPoint checkPointParam = dynamicParam as EntityParamCheckPoint;
                return checkPointParam.isActive;
            }
            return false;
        }

        public EntityDynamicParamType GetPhysicType()
        {
            if (entityConfig == null)
            {
                return EntityDynamicParamType.None;
            }
            EntityParamTriggerRect triggerRect = GetDynamicParam(EntityDynamicParamType.TriggerRect) as EntityParamTriggerRect;
            if (triggerRect != null && triggerRect.isPhysicNavTrigger)
            {
                //获取类型（只能在和切换行走模式相关的类型里筛选）
                foreach (var kv in entityConfig.paramMap)
                {
                    switch (kv.Key)
                    {
                        case EntityDynamicParamType.Elevator:
                        case EntityDynamicParamType.House:
                            return kv.Key;
                        default:
                            break;
                    }
                }
            }
            return EntityDynamicParamType.None;
        }

        public void OnAOIAdd(long playerId)
        {
            _aoiSubscribers.Add(playerId);
        }

        public void OnAOIRemove(long playerId)
        {
            _aoiSubscribers.Remove(playerId);
        }

        public override IPOD GeneratePOD()
        {
            return GeneratePOD(false, true);
        }

        public LevelEntityMapPOD GenerateMapPOD(LevelPlayer player)
        {
            LevelEntityMapPOD pod = new LevelEntityMapPOD();
            pod.id = id;
            pod.mcid = entityConfig.id;
            pod.mapUIEntityCid = entityConfig.mapUIEntityCid;
            pod.x = (int)position.x;
            pod.y = (int)position.y;
            pod.z = (int)position.z;
            Vector3Int eulerV3Int = Vector3Logic.DirectionToEulerXy(dir);
            pod.dir = Vector3Int.ToIntEuler(eulerV3Int);
            pod.isObstacleActive = isObstacleActive;
            pod.isCheckPointActive = isCheckPointActive;
            pod.isOfferingQuest = this.IsOfferingQuest(player);
            pod.isCheckPoint = this.HasDynamicParam(EntityDynamicParamType.CheckPoint);
            return pod;
        }

        public override void OnReset()
        {
            base.OnReset();
            ClassPool.Put(serviceMgr);
            serviceMgr = null;
            foreach (var data in _syncTransDataList)
            {
                ClassPool.Put(data);
            }
            _syncTransDataList.Clear();
            _syncTransElapsedTime = 0;
            SLevelLogicModule.Instance.BehaviacManager.RemoveAgentFrom(this);
            if (stateMachine != null)
            {
                SLevelLogicModule.Instance.StateMachineManager.RemoveFSM(this);
                stateMachine = null;
            }
            _entityConfig = null;
            InitData = default;
            isObstacleActive = false;
            interactType = 0;
            _lastInteractType = 0;
            triggerRect = default;
            triggerRectHalfHeight = 0;
            bvhBounds = default;
            tags?.Clear();
            tags = null;
            isTriggerRectRotated = false;
            execCount = 0;
            _aoiSubscribers.Clear();
        }
    }
}
